package com.highspeed.bdk.service.logic;

import com.highspeed.bdk.bean.entity.logic.App;
import com.highspeed.bdk.bean.entity.logic.LogicLink;
import com.highspeed.bdk.bean.entity.logic.LogicTopology;
import com.highspeed.bdk.bean.entity.physical.PhysicalLink;
import com.highspeed.bdk.bean.entity.physical.PhysicalTopology;
import com.highspeed.bdk.repository.logic.LogicTopologyRepository;
import com.highspeed.bdk.service.base.BdkBaseService;
import com.highspeed.bdk.service.physical.IPhysicalLinkService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * Created by chenjiabin on 2018/3/23.
 */
@Service
@Transactional
public class LogicTopologyService extends BdkBaseService<LogicTopology, Integer> implements ILogicTopologyService {
    private static final Log LOG = LogFactory.getLog(LogicTopologyService.class);
    @Autowired
    private LogicTopologyRepository logicTopologyRepository;
    @Autowired
    private ILogicLinkService logicLinkService;

    @Override
    public LogicTopologyRepository getRepository() {
        return logicTopologyRepository;
    }

    @Override
    public LogicTopology save(LogicTopology entity) {
        initLogicTopology(entity);
        return super.save(entity);
    }


    @Override
    public LogicTopology saveAndFlush(LogicTopology entity) {
        initLogicTopology(entity);
        return super.saveAndFlush(entity);
    }

    @Override
    public <S extends LogicTopology> List<S> save(Iterable<S> entities) {
        if (entities != null) {
            for (LogicTopology mb : entities) {
                initLogicTopology(mb);
            }
        }
        return super.save(entities);
    }


    @Override
    public void delete(Integer[] ids) {
        if (ids != null) {
            List<LogicTopology> tps = new ArrayList<LogicTopology>(0);
            for (Integer id : ids) {
                LogicTopology old = findOne(id);
                if (old != null) {
                    old.setEnabled(false);
                }
                tps.add(old);
            }
            save(tps);
        }
    }

    @Override
    public void delete(Integer id) {
        delete(new Integer[]{id});
    }

    private void initLogicTopology(LogicTopology logicTopology) {
        if (logicTopology.getCreator() == null) {
            logicTopology.setCreator(SecurityContextHolder.getContext().getAuthentication().getName());
        }
        if (logicTopology != null && logicTopology.getApps() != null) {
            for (App item : logicTopology.getApps()) {
                item.setLogicTopology(logicTopology);
            }
        }
    }


    /**
     * @see IPhysicalLinkService
     */
    @Override
    public List<Map<String, Integer>> queryVirtualLinksByLogicTopologyId(Integer id) {
        List<Map<String, Integer>> virtualLinks = new ArrayList<Map<String, Integer>>(0);
        List<LogicLink> links = logicLinkService.findByLogicTopologyId(id);
        Map<String, Map<String, Integer>> linkGroup = groupingCountByCpus(links);
        Set<Map.Entry<String, Map<String, Integer>>> entries = linkGroup.entrySet();
        for (Map.Entry<String, Map<String, Integer>> entry : entries) {
            virtualLinks.add(entry.getValue());
        }
        return virtualLinks;
    }

    /**
     * 将逻辑链接分组统计
     *
     * @param links 逻辑链接
     * @return 统计结果MAP（KEY为左右两个CPU的ID，VALUE为两个CPU之间的连续数量）
     */
    private Map<String, Map<String, Integer>> groupingCountByCpus(List<LogicLink> links) {
        Map<String, Map<String, Integer>> linkGroup = new HashMap<String, Map<String, Integer>>(0);
        for (LogicLink link : links) {
            String key = link.getLeftApp().getId() + "," + link.getRightApp().getId();
            Map<String, Integer> virtualLink = linkGroup.get(key);
            if (virtualLink == null) {
                virtualLink = new HashMap<String, Integer>(0);
                linkGroup.put(key, virtualLink);
                virtualLink.put("leftApp", link.getLeftApp().getId());
                virtualLink.put("rightApp", link.getRightApp().getId());
                virtualLink.put("links", 0);
            }
            virtualLink.replace("links", virtualLink.get("links") + 1);
        }
        return linkGroup;
    }
}
